#pragma once
#include <cstdio>
#include <cstring>
#include <string>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "socket.h"
#include <functional>
#include "esp_log.h"

namespace udp_server
{
    static const char *TAG = "udp_server";
    typedef std::function<void(int, uint16_t, std::string)> func_t;

    class UDPServer
    {
    public:
        UDPServer(const uint16_t port, func_t func) : port_(port), sock_(-1), func_(func)
        {
        }

        ~UDPServer()
        {
            close(sock_);
        }

        void initServer()
        {
            // 创建UDP socket
            sock_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if (sock_ < 0)
            {
                ESP_LOGE(TAG, "socket create failed\n");
                return;
            }
            else
            {
                ESP_LOGI(TAG, "socket create success\n");
            }

            // 绑定UDP socket到指定端口
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port_);
            addr.sin_addr.s_addr = htonl(INADDR_ANY);
            if (bind(sock_, (struct sockaddr *)&addr, sizeof(addr)) < 0)
            {
                ESP_LOGE(TAG, "bind failed\n");
                return;
            }
            else
            {
                ESP_LOGI(TAG, "bind success\n");
            }
        }

        void start()
        {
            char buffer[1024];
            for (;;)
            {
                // 接收UDP数据
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                ssize_t s = recvfrom(sock_, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client_addr, &client_addr_len);
                if (s < 0)
                {
                    ESP_LOGW(TAG, "recvfrom failed\n");
                    continue;
                }
                else
                {
                    ESP_LOGI(TAG, "recvfrom success\n");
                    buffer[s] = 0;
                    std::string clientip = inet_ntoa(client_addr.sin_addr); // 获取客户端IP地址
                    uint16_t clientport = ntohs(client_addr.sin_port);      // 获取客户端端口号
                    std::string message = buffer;
                    printf("%s[%d]# %s\n", clientip.c_str(), clientport, message.c_str());
                    func_(sock_, clientport, message);
                }
            }
        }

    private:
        uint16_t port_;
        int sock_;
        func_t func_;
    };
}